package cn.mysdp.biz.facade;

import cn.mysdp.biz.domain.*;
import cn.mysdp.biz.dto.request.*;
import cn.mysdp.biz.repository.*;
import cn.mysdp.http.SDPHttpException;
import cn.mysdp.http.SDPHttpResult;
import cn.mysdp.utils.JavaBeansUtil;
import cn.mysdp.utils.SplitUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @ClassName:
 * @Description:
 * @Author: SDP
 * @Date: 2020-06-01
 * @Version:1.0
 * Table:
 * Comment:
 *
 */
@Service
public class BaseServiceImpl {
    @Autowired
    SdpHistoryMapper sdpHistoryMapper;

    @Autowired
    SdpWorkspaceMapper sdpWorkspaceMapper;

    @Autowired
    SdpWorkspaceConfigMapper sdpWorkspaceConfigMapper;

    @Autowired
    SdpProjectMapper sdpProjectMapper;

    @Autowired
    SdpTemplateMapper sdpTemplateMapper;

    @Autowired
    SdpSqlMapper sdpSqlMapper;

    public static Map<String, String> beanClassNameMap = new ConcurrentReferenceHashMap<>();
    public static Map<String, String> listMethodNameMap = new ConcurrentReferenceHashMap<>();
    public static Map<String, String> listMethodParameterClassNameMap = new ConcurrentReferenceHashMap<>();
    public static Map<String, String> updateMethodNameMap = new ConcurrentReferenceHashMap<>();
    public static Map<String, String> updateMethodParameterClassNameMap = new ConcurrentReferenceHashMap<>();

    @Autowired
    protected HttpServletRequest httpServletRequest;

    @Autowired
    protected HttpServletResponse httpServletResponse;

    public void fixRequest(String module, String method, Object request) throws Exception {
        fixRequest(module, method, request, null);
    }

    public void fixRequest(String module, String method, Object request, Object record) throws Exception {
        if (request instanceof BaseRequest) {
            BaseRequest baseRequest = (BaseRequest)request;
            baseRequest.checkParam();
        }
        SimpleDateFormat datetimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        httpServletResponse.setHeader("server_tsp", datetimeFormat.format(new Date()));
    }

    public void assertNotNull(Object object, String msg) throws Exception {
        if (null == object) {
            throw new Exception("miss param:" + msg);
        }
    }

    public boolean needCheckDeleteList(BaseRequest request) {
        return false;
    }

    public void addErrorInfo(Exception ex) {

    }

    public void checkNotEmpty(Object object, String remark) throws Exception {
        if (object == null) {
            throw new Exception("miss param: "+remark);
        }
        if (object instanceof String) {
            if (!StringUtils.hasText((String) object)) {
                throw new Exception("miss param: "+remark);
            }
        }
    }

    public static String getExceptionMessage(Exception exIn) {
        Throwable ex = exIn;
        if (exIn instanceof InvocationTargetException && ((InvocationTargetException) exIn).getTargetException() != null) {
            InvocationTargetException targetException = (InvocationTargetException) exIn;
            if(targetException.getTargetException() instanceof Exception) {
                ex = (Exception)targetException.getTargetException();
            } else {
                ex = targetException.getTargetException();
            }
        }
        if (ex == null) {
            ex = exIn;
        }

        if (ex instanceof DuplicateKeyException || (ex != null && ex.getMessage() != null && ex.getMessage().indexOf("Duplicate entry") >= 0)) {
            return "违反唯一性限制:"+ex.getMessage().split("SQL:")[0];
        } else {
            return ex.getMessage();
        }
    }

    public Exception createFailException(Exception ex) {
        if (ex instanceof DuplicateKeyException || ex.getMessage().indexOf("Duplicate entry") >= 0) {
            return new Exception(ex.getMessage().split("SQL:")[0]);
        } else {
            return new Exception(ex.getMessage());
        }
    }

    public int maxDeleteMillSeconds() {
        return 100000;
    }

    public int maxDeleteCount() {
        return 10000000;
    }

    public void addLog(BaseRequest request, String msg) {
    }

    public void addHistory(BaseRequest request, String op, String type, String info, Object keyId, String keyName, String shopName) {
        if ("sdp_history".equals(type)) {
            return;
        }
        String workspaceName = "";

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("op", op);
        jsonObject.put("info", info);
        if (keyId != null) {
            jsonObject.put("keyId", keyId);
        }
        if (keyName != null) {
            jsonObject.put("keyName", keyName);
        }

        //屏蔽敏感信息
        if (request instanceof SdpWorkspaceAddRequest) {
            SdpWorkspaceAddRequest newRequest = new SdpWorkspaceAddRequest();
            BeanUtils.copyProperties(request, newRequest);
            newRequest.setDbPassword(null);
            request = newRequest;
        } else if (request instanceof SdpWorkspaceUpdateRequest) {
            SdpWorkspaceUpdateRequest newRequest = new SdpWorkspaceUpdateRequest();
            BeanUtils.copyProperties(request, newRequest);
            newRequest.setDbPassword(null);
            request = newRequest;
        }

        jsonObject.put("obj", request);

        if (keyId != null && keyId instanceof Integer) {
            Object record = null;
            if ("sdp_workspace".equals(type)) {
                record = sdpWorkspaceMapper.selectByIdWithBLOBs((Integer) keyId);
            } else if ("sdp_workspace_config".equals(type)) {
                record = sdpWorkspaceConfigMapper.selectByIdWithBLOBs((Integer) keyId);
            } else if ("sdp_project".equals(type)) {
                record = sdpProjectMapper.selectByIdWithBLOBs((Integer) keyId);
            } else if ("sdp_template".equals(type)) {
                record = sdpTemplateMapper.selectByIdWithBLOBs((Integer) keyId);
            } else if ("sdp_sql".equals(type)) {
                record = sdpSqlMapper.selectByIdWithBLOBs((Integer) keyId);
            }
            if (record != null) {
                //屏蔽敏感信息
                if (record instanceof SdpWorkspaceWithBLOBs) {
                    ((SdpWorkspaceWithBLOBs)record).setDbPassword(null);
                }

                jsonObject.put("record", record);
            }
        }
        SdpHistoryWithBLOBs history = new SdpHistoryWithBLOBs();
        history.setWorkspaceName(workspaceName);
        history.setTableName(type);
        history.setContent(JSON.toJSONString(jsonObject));
        sdpHistoryMapper.insertSelective(history);
        SdpHistoryExample example = new SdpHistoryExample();
        example.setOrderByClause("id desc limit 1001");
        List<SdpHistory> list = sdpHistoryMapper.selectByExample(example);
        if (!CollectionUtils.isEmpty(list) && list.size() > 1000) {
            Integer id = list.get(list.size() - 1).getId();
            example = new SdpHistoryExample();
            example.createCriteria().andIdLessThanOrEqualTo(id);
            sdpHistoryMapper.deleteByExample(example);
        }
    }

    public Field getField(Class clz, String name) {
        return JavaBeansUtil.getField(clz, name);
    }

    public void addHistory(BaseRequest request, String op, String type, String info, Object keyId, String keyName) {
        addHistory(request, op, type, info, keyId, keyName, null);
    }

    public void fixEqualCondition(BaseRequest request, String module, String method, String fieldName, List<Criterion> criteria) {
        if ("add".equals(method) ||
                "update".equals(method) ||
                "delete".equals(method)) {
            return;
        }
    }

    public void checkInternalId(BaseRequest request, String module, String method, Object id) {

    }

    public void checkResult(String module, String method, BaseRequest request) throws Exception {
        checkResult(module, method, request, null);
    }

    public void checkResult(String module, String method, BaseRequest request, Object result) throws Exception {

    }

    public BaseNameRequest createBaseNameRequest(String name) {
        BaseNameRequest request = new BaseNameRequest();
        request.setName(name);
        return request;
    }

    public void copyProperties(Object source, Object target) throws Exception {
        BeanUtils.copyProperties(source, target);
    }

    public void checkLowercaseName(String name) throws Exception {
        String validChars = "abcdefghijklmnopqrstuvwxyz1234567890_";
        checkName(name, validChars, "必须为小写字母、数字、下滑线");
    }

    public void checkLowercaseNameWithDot(String name) throws Exception {
        String validChars = "abcdefghijklmnopqrstuvwxyz1234567890_.";
        checkName(name, validChars, "必须为小写字母、数字、下滑线、小数点");
    }

    public void checkName(String name, String validChars, String tip) throws Exception {
        if (!StringUtils.isEmpty(name)) {
            for (char c : name.toCharArray()) {
                if (validChars.indexOf(c) < 0) {
                    throw new Exception("名称非法，"+tip+"："+name);
                }
            }
        }
    }

    public void addHistory(Object object, String tableName) {
        if ("sdp_history".equals(tableName)) {
            return;
        }
        String workspaceName = "";
        String fieldName = "workspaceName";
        if ("sdp_workspace".equals(tableName)) {
            fieldName = "name";
        }
        Field field = getField(object.getClass(), fieldName);
        if (field != null) {
            try {
                workspaceName = (String) field.get(object);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        SdpHistoryWithBLOBs history = new SdpHistoryWithBLOBs();
        history.setWorkspaceName(workspaceName);
        history.setTableName(tableName);
        history.setContent(JSON.toJSONString(object));
        sdpHistoryMapper.insertSelective(history);
    }

    public void checkNonNull(Object object, String msg) {
        if (null == object) {
            throw new SDPHttpException(SDPHttpResult.FAIL,"miss param:" + msg);
        }
    }

    public SDPHttpException createFailException(String msg) {
        return new SDPHttpException(SDPHttpResult.FAIL, msg);
    }

    public SDPHttpException createUpdateFailException() {
        return new SDPHttpException(SDPHttpResult.E2004, SDPHttpResult.E2004.getMsg());
    }

    public SDPHttpException createDatabaseFailException(Exception ex) {
        ex.printStackTrace();
        String msg = SplitUtil.split(ex.getMessage(), " error")[0];
        if (msg.length() > 200) {
            msg = msg.substring(0, 200);
        }
        return new SDPHttpException(SDPHttpResult.FAIL, msg);
    }

    public SDPHttpException checkDBDupException(Exception ex, Map<String, String> map) throws SDPHttpException {
        String exMessage = ex.getMessage();
        Integer dupIndex = exMessage.indexOf("Duplicate entry '");
        Integer forKeyIndex = exMessage.indexOf("' for key ", dupIndex);
        if (dupIndex >= 0 && forKeyIndex >= 0) {
            String errInfo = exMessage.substring(dupIndex + "Duplicate entry '".length(), forKeyIndex);
            String keyName = SplitUtil.split(exMessage.substring(forKeyIndex + 1), "'")[1];
            if (map.containsKey(keyName)) {
                return new SDPHttpException(SDPHttpResult.FAIL, "已经存在：" + errInfo + "(" + map.get(keyName) + ")");
            }
        }
        return new SDPHttpException(SDPHttpResult.FAIL, ex.getMessage());
    }

    void clearPageInfo(BaseRequest request) {
        if(request.getQueryOptions() != null) {
            request.getQueryOptions().remove("count");
            request.getQueryOptions().remove("limit");
        }
        request.setPageNo(null);
        request.setPageSize(null);
    }

}
